using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Threading;

namespace PatternMaker
{
	abstract public class PatternGenerator
	{
		public static Bitmap ScaleImage(Bitmap imgPhoto, int scale)
		{
			int Percent = (int)(scale * 100);
			float nPercent = ((float)Percent / 100);

			int sourceWidth = imgPhoto.Width;
			int sourceHeight = imgPhoto.Height;
			int sourceX = 0;
			int sourceY = 0;

			int destX = 0;
			int destY = 0;
			int destWidth = (int)(sourceWidth * nPercent);
			int destHeight = (int)(sourceHeight * nPercent);

			Bitmap bmPhoto = new Bitmap(destWidth, destHeight,
															 PixelFormat.Format24bppRgb);
			bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
															imgPhoto.VerticalResolution);

			Graphics grPhoto = Graphics.FromImage(bmPhoto);
			grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;

			grPhoto.DrawImage(imgPhoto,
					new Rectangle(destX, destY, destWidth, destHeight),
					new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
					GraphicsUnit.Pixel);

			grPhoto.Dispose();
			return bmPhoto;
		}


		public event EventHandler Complete;
		public event EventHandler<ExceptionEventArgs> ExceptionOccurred;
		public event EventHandler<ProgressEventArgs> ProgressChanged;
		public event EventHandler Started;


		private int _cellCountHorizontal;
		private int _cellCountVertical;
		private int _cellHeight;
		private int _cellWidth;
		private Bitmap _colourChart;
		private Dictionary<int, char> _colourCodes = new Dictionary<int, char>();
		private int _colourTolerance = 25;
		private Font _font;
		private Bitmap _original;
		private bool _parametersChanged;
		private Bitmap _pattern;
		private Bitmap _patternThumbnail;
		private int _scale = 1;
		private Thread _thread;


		public int CellCountHorizontal
		{
			get { return _cellCountHorizontal; }
			set
			{
				if (value != _cellCountHorizontal)
				{
					_cellCountHorizontal = value;
					ParametersChanged = true;
					if (Original != null) CellWidth = Original.Width / _cellCountHorizontal;
				}
			}
		}

		public int CellCountVertical
		{
			get { return _cellCountVertical; }
			set
			{
				if (_cellCountVertical != value)
				{
					_cellCountVertical = value;
					ParametersChanged = true;
					if (Original != null) CellHeight = Original.Height / _cellCountVertical;
				}
			}
		}

		protected int CellHeight
		{
			get { return _cellHeight; }
			set
			{
				if (_cellHeight != value)
				{
					_cellHeight = value;
					ParametersChanged = true;
				}
			}
		}

		protected int CellWidth
		{
			get { return _cellWidth; }
			set
			{
				if (_cellWidth != value)
				{
					_cellWidth = value;
					ParametersChanged = true;
				}
			}
		}

		public Bitmap ColourChart
		{
			get { return _colourChart; }
			set { _colourChart = value; }
		}

		public Dictionary<int, char> ColourCodes
		{
			get { return _colourCodes; }
			set { _colourCodes = value; }
		}

		public int ColourTolerance
		{
			get { return _colourTolerance; }
			set
			{
				if (ColourTolerance != value)
				{
					_colourTolerance = value;
					ParametersChanged = true;
				}
			}
		}

		public Font Font
		{
			get { return _font; }
			set { _font = value; }
		}

		public Bitmap Original
		{
			get { return _original; }
			set
			{
				if (value != null)
				{
					_original = (Bitmap)value.Clone();
					CellWidth = _original.Width / CellCountHorizontal;
					CellHeight = _original.Height / CellCountVertical;
				}
			}
		}

		public bool ParametersChanged
		{
			get { return _parametersChanged; }
			protected set { _parametersChanged = value; }
		}

		public Bitmap Pattern
		{
			get { return (Bitmap)InnerPattern.Clone(); }
		}

		protected Bitmap InnerPattern
		{
			get { return _pattern; }
			set { _pattern = value; }
		}

		public Bitmap PatternThumbnail
		{
			get { return (Bitmap)InnerPatternThumbnail.Clone(); }
		}

		protected Bitmap InnerPatternThumbnail
		{
			get { return _patternThumbnail; }
			set { _patternThumbnail = value; }
		}

		public int Scale
		{
			get { return _scale; }
			set { _scale = value; }
		}

		private Thread Thread
		{
			get { return _thread; }
			set { _thread = value; }
		}


		protected void ApplyGrid(Image image)
		{
			Graphics g = Graphics.FromImage(image);
			Pen p = new Pen(Color.Black);

			for (int x = 0; x <= image.Width; x += CellWidth * Scale)
			{
				g.DrawLine(p, x, 0, x, image.Height);
			}

			for (int y = 0; y <= image.Height; y += CellHeight * Scale)
			{
				g.DrawLine(p, 0, y, image.Height, y);
			}
		}

		public void Begin()
		{
			if (Thread == null || !Thread.IsAlive)
			{
				Thread = new Thread(new ThreadStart(BeginExecute));
				Thread.Start();
			}
		}

		private void BeginExecute()
		{
			try
			{
				OnStarted(new EventArgs());
				Execute();
				OnComplete(new EventArgs());
				ParametersChanged = false;
			}
			catch (ThreadAbortException)
			{
			}
			catch (Exception ex)
			{
				OnExceptionOccurred(new ExceptionEventArgs(ex));
			}
		}

		public void Cancel()
		{
			if (Thread != null)
			{
				if (Thread.IsAlive) Thread.Abort();
				Thread = null;
			}
		}

		abstract protected void Execute();

		virtual protected void OnComplete(EventArgs e)
		{
			if (Complete != null) Complete(this, e);
		}

		virtual protected void OnExceptionOccurred(ExceptionEventArgs e)
		{
			if (ExceptionOccurred != null) ExceptionOccurred(this, e);
		}

		virtual protected void OnProgressChanged(ProgressEventArgs e)
		{
			if (ProgressChanged != null) ProgressChanged(this, e);
		}

		virtual protected void OnStarted(EventArgs e)
		{
			if (Started != null) Started(this, e);
		}

		abstract public void Preview();
	}
}
